![]() |
![]() |
|
Der intuitive Normalfall bei der Entwicklung eines Programms in einer prozeduralen Programmiersprache ist es, dass der Programmablauf durch den von Ihnen geschriebenen Code bestimmt wird. Sie schreiben auf, was ausgeführt werden soll, und genau in dieser Reihenfolge passiert es dann auch. Mit den Mitteln der objektorientierten Programmierung wird bereits ein relevanter Teil der Ablaufsteuerung nicht mehr explizit beschrieben, sondern an Mechanismen der Programmiersprache abgegeben. Bei Aufruf einer polymorphen Operation entscheidet der Typ eines Objekts zur Laufzeit darüber, welche Methode nun genau aufgerufen wird. Wenn Sie nun aber die Kontrolle darüber, wann im Programmablauf unsere implementierte Funktionalität tatsächlich aufgerufen wird, an ein anderes Modul abgeben, sprechen wir von einer Umkehrung des Kontrollflusses. Frameworks sind Zusammenstellungen von Klassen, die den Rahmen für den Ablauf von solchen Anwendungen liefern. Eine Anwendung, die ein Framework nutzt, ist damit von der Aufgabe entbunden, den Kontrollfluss selbst zu steuern. Sie stellt nur noch im Rahmen dieses Kontrollflusses benötigte fachliche Implementierungen zur Verfügung, der Kontrollfluss ist damit umgekehrt worden. Schablonenmethoden Ebenfalls häufig in Frameworks anzutreffen sind neben den bereits erwähnten Fabriken die Schablonenmethoden. Wir haben diese in Abschnitt 5.3.1, Überschreiben von Methoden, bereits vorgestellt. Schablonenmethoden geben einen Rahmen vor, innerhalb dem Operationen aufgerufen werden, die erst von abgeleiteten Klassen implementiert werden müssen. Dadurch können Frameworks über abstrakte Klassen eine Sequenz von Aktionen steuern. In Abschnitt 8.2 werden Sie den Ansatz Model-View-Controller (MVC) für die Steuerung des Kontrollflusses in der Präsentationsschicht kennen lernen. In einem MVC-Framework können zum Beispiel die Klassen, die für konkrete Darstellungen auf dem Bildschirm zuständig sind, als Ableitungen von abstrakten Klassen umgesetzt werden. Diese müssen dann für ihre korrekte Aktualisierung sorgen. Die Erstellung dieser auch Views genannten Klassen und die Interaktion mit anderen Komponenten kann jedoch vom Framework übernommen werden. Swing, MFC Typische Beispiele sind hierbei Frameworks, die den Ablauf für Interaktionen an einer Benutzeroberfläche steuern. So bringen zum Beispiel die GUI-Frameworks Swing und Microsoft Foundation Classes (MFC) Bestandteile mit, die generell die Interaktion innerhalb eines MVC-Ansatzes regeln. Die vom Anwendungsprogrammierer eingebrachten Module fügen sich in den Ablauf des Frameworks ein. Die neu umgesetzte Funktionalität wird vom Framework innerhalb dessen eigenem Kontrollfluss aufgerufen. Frameworks: Probleme Frameworks haben allerdings in der Praxis mit ein paar Problemen zu kämpfen. Das Hauptproblem ist dabei, die vorzusehenden Erweiterungspunkte zu bestimmen, ohne schon alle konkreten Anwendungsfälle zu kennen. Werden zu wenige oder die falschen Erweiterungspunkte eingebaut, ist das Framework zu unflexibel. Werden zu viele Erweiterungspunkte eingebaut, wird das Framework zu komplex und schwierig zu warten. Was soll erweiterbar sein? In der Praxis ist es nicht einfach, die Punkte zu bestimmen, die für Erweiterungen zugänglich sein sollen. Oft wird zu viel von den Eigenschaften der Framework-Klassen öffentlich gemacht. Ist diese öffentlich gemachte Information dann einmal von Framework-Anwendern verwendet worden, kann sie praktisch nicht mehr geändert werden und verhindert zu einem gewissen Grad notwendige Umbauarbeiten innerhalb des Frameworks. Nach unserer Erfahrung hat ein Framework diesen Zustand erreicht, wenn häufiger der Satz fällt: »Aber ihr verwendet das Framework doch ganz falsch! Dafür war diese Methode nie gedacht!« In diesem Fall wurde zu viel von den Interna des Frameworks offen gelegt, oder dieses ist einfach insgesamt zu komplex geworden. Frameworks haben sich deshalb meist dort bewährt, wo sie für einen klar definierten und überschaubaren Einsatzbereich konzipiert worden sind. Ein gutes Beispiel ist das JUnit-Framework, das erfolgreich für den Test von Java-Modulen eingesetzt wird. Zunächst einmal weist JUnit ein sauberes Design auf. Ein weiterer sehr wichtiger Punkt ist aber, dass der von JUnit abgedeckte Bereich so eingegrenzt ist, dass die notwendigen Erweiterungspunkte des Frameworks überschaubar geblieben sind. Deshalb ist JUnit für den gewählten Einsatzbereich auch so nützlich und stabil. Erst die Erweiterung der Sprache Java um die Annotations führte zu größeren Änderungen von JUnit. Frameworks für technische Abläufe In den meisten Anwendungsfällen versuchen Frameworks, die technischen Abläufe zu kapseln, so dass die Umsetzung der Fachlichkeit erfolgen kann, ohne sich mit allen technischen Details beschäftigen zu müssen. JUnit und die bereits erwähnten MVC-Frameworks sind Beispiele hierfür. Komplexer wird die Aufgabenstellung, wenn Gemeinsamkeiten von fachlichen Abläufen und Objekten über ein Framework strukturiert werden sollen. Sofern dies innerhalb eines Unternehmens mit einer weitgehend homogenen Sicht auf Objekte und Prozesse geschieht und außerdem das entstehende Framework auf beobachteten Gemeinsamkeiten verschiedener Bereiche basiert, ist eine Framework-Umsetzung auch noch aussichtsreich. Fachliche Frameworks Die Ausdehnung von Frameworks auf die Fachlichkeit von Geschäftsanwendungen über verschiedene Unternehmen und Branchen hinweg hat sich dagegen als sehr komplexe Aufgabe erwiesen. IBM hat mit den San Francisco Framework Classes gegen Ende der 90er-Jahre einen Versuch unternommen, Frameworks auf den fachlichen Bereich von Unternehmensanwendungen auszudehnen. Ziel war es dabei, die Gemeinsamkeiten von Geschäftsobjekten und der zugeordneten Prozesse über ein fachliches Framework abzubilden. Die spezifischen Ausprägungen sollten dann über die Mittel der zur Verfügung stehenden Erweiterungspunkte an die fachlichen Anforderungen erfolgen. Die San Francisco Classes wurden allerdings nie wirklich erfolgreich. Microsoft arbeitet mit den Microsoft Business Classes an einem neuen Versuch, mit dem es aber noch keine praktischen Erfahrungen gibt. Nach unserer Einschätzung sind Frameworks, die relevante Teile von Fachlichkeit bereits abbilden, nur dann realistisch einsetzbar, wenn nicht nur das Framework, sondern auch die Geschäftsprozesse selbst anpassbar sind. Der klassische Ansatz von SAP illustriert das, dort gibt die Software einen relevanten Teil der Prozesse vor, ein nutzendes Unternehmen muss sich weitgehend daran anpassen. ContainerIn der Praxis hat sich eine besondere Form von Frameworks etabliert, deren Fokus darauf liegt, den Lebenszyklus von Objekten selbst zu verwalten. Diese Frameworks werden als Container bezeichnet.
Container im Allgemeinen sind aber Laufzeitumgebungen, in denen Objekte verwaltet werden und dort bestimmte Services nutzen können. Es ist also nicht grundsätzlich notwendig, dass ein solcher Container Teil eines Applikationsserver ist. Leichtgewichtige Container Diese Bindung an Applikationsserver aufzuheben ist eine Zielsetzung der so genannten leichtgewichtigen Container. Ein Beispiel für solche Container ist der Ansatz des Spring-Frameworks, bei dem die fachlichen Klassen alle als einfache Java-Klassen, so genannte Pojos, umgesetzt werden.3 Dependency InjectionDen Mechanismus der Dependency Injection haben wir bereits in Abschnitt 7.2.7 beschrieben. Dependency Injection ist ein Mechanismus, der als Bestandteil einer Architektur verwendet werden kann. Über Dependency Injection werden die Abhängigkeiten zwischen genutzten Modulen und ihren Nutzern aus dem Code extrahiert. Der Container, der unsere Objekte verwaltet, ist dafür zuständig, die genutzten Objekte bereitzustellen. Die Entscheidung, ob dabei ein einziges Exemplar ausreicht oder ob für jeden Nutzungsfall ein eigenes Exemplar notwendig ist, liegt in der Konfiguration beziehungsweise beim Container. Bei Nutzung dieses Mechanismus ist es zum Beispiel auch nicht mehr notwendig, mit Singletons zu arbeiten. Ein Singleton wäre in diesem Fall durch Konfiguration über den Container zu erreichen, wir haben aber bei keiner Klasse mehr die unbedingte Voraussetzung, dass nur ein Exemplar davon existieren kann. PluginsAm Beispiel der freien Entwicklungsplattform Eclipse ist zu sehen, dass sich komplexe Applikationen auch auf der Grundlage von so genannten Plugins aufbauen lassen. Plugin ist wieder ein recht schillernder Begriff. Wir setzen unsere Definition auf der Beschreibung von Martin Fowler auf, der eine große Erfahrung in der Definition von schwammigen Begriffen mitbringt.4
Plugins, wie sie von Eclipse verwendet werden, basieren auf der Definition von Erweiterungspunkten. Hier ist es zum einen möglich, eigene Erweiterungen einzubringen. Auf der anderen Seite können diese aber bereits wieder selbst Erweiterungsmöglichkeiten definieren, so dass eine gestaffelte Erweiterung der Plattform möglich wird. Diese Möglichkeit wird von Eclipse ganz klassisch als Konzept der Erweiterungspunkte (extension points) bezeichnet. Es deutet einiges darauf hin, dass Eclipse mit diesem Konzept zumindest für den zunächst gewählten Anwendungsbereich (nämlich eine Entwicklungsplattform) auf einem guten Weg ist. Der Ansatz vermeidet viele Fallen der klassischen Frameworks und hält die Komplexität durch seine klare Aufgabentrennung über Erweiterungspunkte in überschaubarem Rahmen. Einfacher Einbau der Erweiterungspunkte Was hier ebenfalls wichtig ist und was nicht bei allen Komponentenmodellen bisher beachtet wurde: Es muss einfach sein, einen Erweiterungspunkt einzubauen, sobald klar wird, dass dieser benötigt wird. Damit sind wir nicht gezwungen, von vornherein alle möglichen Erweiterungspunkte in unserem Modul vorwegzunehmen. 1 Als Konsequenz ist dann ein Softwarearchitekt in einem Projekt jemand, der wichtig ist oder dessen Meinung schwer zu ändern ist. 2 Wir haben die Umkehrung des Kontrollflusses bereits in Abschnitt 3.6, Umkehr der Abhängigkeit, an einem Beispiel vorgestellt. 3 Der Begriff Pojo für Plain Old Java Objects wurde von Martin Fowler eingeführt. Die Motivation war, den guten alten Java-Klassen durch einen hippen Namen wieder zu mehr Präsenz zu verhelfen. Überhaupt gelingt es Martin Fowler häufig, Begriffe für Vorgehensweisen und Sachverhalte zu prägen. So stammt auch der Begriff Dependency Injection für eine bestimmte Form der Umkehrung des Kontrollflusses von ihm und Rod Johnson. Value Objects in der J2EE-Spezifikation wurden zu Data Transfer Objects, nachdem Martin Fowler diese Benennung kritisiert hatte. 4 Siehe auch [Fowler 2003] oder auch http://www.martinfowler.com/eaaCatalog/plugin.html.
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.